로딩 중이에요... 🐣
4. 관계형 필드 | ✅ 저자: 이유정(박사)
- ForeignKey는 "한 개의 객체(ModelB)가 여러 객체(ModelA)에 연결될 수 있도록" 해줍니다.
- 예시:
- 앨범-노래: 한 앨범에 여러 곡이 들어감 (곡 → 앨범: ForeignKey)
- 글-카테고리: 여러 개의 글이 하나의 카테고리에 속함 (글 → 카테고리: ForeignKey)
models.py
category = models.ForeignKey(...)
ForeignKey(Category)
: Post는 Category에 연결된다 = 글은 하나의 카테고리에 속한다on_delete=models.CASCADE
: 카테고리가 삭제되면 관련 글도 함께 삭제됨related_name='posts'
: Category 입장에서 "이 카테고리에 속한 글들"을category.posts.all()
처럼 참조 가능
views.py : 이 예제에서 핵심은 Post
모델이 Category
모델에 외래키(ForeignKey)로 연결되어 있다는 구조입니다.
Category("프로그래밍") <-- Post A
<-- Post B
<-- Post C
- Category는 1개, Post는 여러 개
- 즉, 1:N 구조 (OneToMany)
post.category
→ 글에서 카테고리 접근category.posts.all()
→ 카테고리에서 모든 글 접근
한 객체가 다른 하나의 객체와 딱 하나만 연결되는 관계
예시: 사람 ↔ 주민등록증 , 사용자(User) ↔ 프로필(UserProfile)
UserProfile
은 하나의 User만 연결될 수 있음- 반대로 하나의
User
도 자신의 UserProfile 하나만 가질 수 있음 OneToOneField 사용 예시:
User.objects.get()
으로 특정 유저 인스턴스를 가져옵니다.user.userprofile
은 OneToOneField 덕분에 자동으로 연결된 UserProfile에 접근할 수 있게 됩니다.user_profile.bio
를 통해 프로필의 소개글을 출력합니다.
다음과 같은 경우 다대다 관계를 사용합니다:
한 권의 책이 여러 저자를 가질 수 있고, 저자도 여러 책을 쓸 수 있음
Book ↔ Author
사용자가 여러 그룹에 가입할 수 있고, 그룹도 여러 사용자를 가질 수 있음
User ↔ Group
게시글에 여러 태그, 태그는 여러 게시글에 사용됨
Post ↔ Tag
→ 핵심: A가 여러 B와 연결되고, B도 여러 A와 연결됨
Book
모델에서Author
와 다대다 관계를 설정- Django가 자동으로 중간 테이블을 생성해줍니다
어떤 상황에 적합한가?
- 단순히 두 모델 간의 연결만 필요할 때
- 중간 관계에서 추가 정보(역할, 날짜 등)가 필요 없는 경우
예제: 저자 ↔ 책 ↔ 역할 정보
왜
through='Authorship'
을 사용하는가?
Django 기본 ManyToMany 관계는 "누가 누구와 연결되어 있는지"만 저장합니다.
하지만 예를 들어: “이 저자가 공동 저자인지, 편집자인지 역할까지 저장하고 싶다!” 이럴 때는 중간 테이블에 직접 정보를 추가해야 하므로, 중간 테이블을 명시적으로 만들어야 합니다.
언제 중간 테이블을 써야 할까?
예시 | 모델1 | 모델2 | 중간 테이블이 필요한 이유 |
---|---|---|---|
책과 저자 | Book | Author | 저자의 역할 (저자/편집자 등)을 추가하고 싶음 |
사용자와 팀 | User | Team | 가입 날짜, 권한 정보를 저장하고 싶음 |
학생과 강의 | Student | Course | 수강 점수, 출석률을 저장하고 싶음 |
상품과 주문 | Product | Order | 수량, 단가 등의 정보가 필요함 |
→ 공통점: 단순 연결 외에 "추가 정보"가 필요한 경우는 중간 테이블을 반드시 만들어야 함 |
ManyToManyField 풀코드: models.py
중간 테이블(Authorship
)의 역할
- 중간 테이블이 없을 때:
- 책과 저자 사이에 단순히 연결만 됩니다.
- 누가 어떤 책을 썼는지만 알 수 있음 (기계적으로 연결만 존재)
- 중간 테이블이 있을 때:
- 이제 우리는 단순히 "이 사람이 이 책에 참여했다"를 넘어서,
- "어떤 방식으로 참여했는가"를 알 수 있게 됩니다!
role = models.CharField(
max_length=10,
choices=AUTHOR_ROLE_CHOICES,
default='WRITER'
)
return f"{self.author.name} - {self.book.title} ({self.role})"
choices
: 고정된 목록으로만 입력 가능하게 함default='WRITER'
: 기본값은 일반 저자
예시 출력결과:
김작가 - Django 완전정복 (WRITER)
박편집자 - Django 완전정복 (EDITOR)
→ 이렇게 누가 어떤 책에 어떤 역할로 참여했는지 명확하게 구분할 수 있습니다.